package cn.imokay.juc.future;

import java.util.concurrent.*;

/**
 * 4组api，将通过4个test方法进行展示
 */
public class CompletableFurtureAPIDemo {

    /**
     * 获得结果，触发计算
     */
    private static void test1() throws ExecutionException, InterruptedException, TimeoutException {
        ExecutorService pool = Executors.newFixedThreadPool(2);
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return "999";
        }, pool);

        //System.out.println(future.get());//不见不散
        //System.out.println(future.get(2,TimeUnit.SECONDS));//过时不候
        //System.out.println(future.join());//与join类似，区别是不会抛出异常
        //System.out.println(future.getNow("888"));//不阻塞，没执行完就直接返回缺省值
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(future.complete("8888"));//如果没执行完，会被打断，返回true，后去的join和get获取的都是缺省值
        System.out.println(future.join());
        pool.shutdown();

    }

    /**
     * 结果处理，有返回值，两个参数的结果处理时，第二个是异常，出现了异常时，只有能接得住异常的方法才能继续执行
     *
     * @throws ExecutionException
     * @throws InterruptedException
     * @throws TimeoutException
     */
    private static void test2() throws ExecutionException, InterruptedException, TimeoutException {
        ExecutorService pool = Executors.newFixedThreadPool(2);
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("111");
            return 1;
        }, pool).thenApply(v -> {
            //如果抛错，会终止
            System.out.println("222");
            int i = 1 / 0;
            return v * 2;
        }).handle((v, e) -> {
            System.out.println("进入handler");
            if (e != null) {
                System.out.println(e.getMessage());
            }
            if (v == null) {
                return 8;
            } else {
                return v * 2;
            }
        }).thenApply(v -> {
            System.out.println("333");
            return v * 3;
        }).whenComplete((v, e) -> {
            System.out.println("进入complte");
            if (e == null) {
                System.out.println("最终结果：" + v);
            } else {
                System.out.println(e.getMessage());
            }
        }).exceptionally(e -> {
            //e.printStackTrace();
            System.out.println("进入exceptionally");
            System.out.println(e.getMessage());
            return null;
        });

        System.out.println("主线程结束");
        pool.shutdown();
    }

    /**
     * 消费结果，没有返回值
     */
    public static void test3() {
        ExecutorService pool = Executors.newFixedThreadPool(2);
       CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return "999";
        }, pool).thenAccept(System.out::println);


       //输出null,thenRun另起线程，无参数无返回，所以join的得到null
        System.out.println(CompletableFuture.supplyAsync(() -> "resultA", pool).thenRun(() -> {}).join());
        //thenAccept消费输出resultA，但是没有返回值，所以join得到null
        System.out.println(CompletableFuture.supplyAsync(() -> "resultA", pool).thenAccept(System.out::println).join());
        //thenApply 有参数，有返回，所以join得到resultABBB
        System.out.println(CompletableFuture.supplyAsync(() -> "resultA", pool).thenApply(v->v+"BBB").join());


        //加了Async的api，默认会另起默认线程池，后续也会一直使用默认线程池
        CompletableFuture.supplyAsync(() -> {
                    try { TimeUnit.SECONDS.sleep(1); } catch (Exception e) { e.printStackTrace();}
                    System.out.println(Thread.currentThread().getName());
                    return "999";},pool)
                .thenRun(()->{System.out.println(Thread.currentThread().getName());})
                .thenRunAsync(()->{System.out.println(Thread.currentThread().getName());})
                .thenRun(()->{System.out.println(Thread.currentThread().getName());})
        ;

        pool.shutdown();

    }

    /**
     * 对计算速度进行选用
     */
    public static void test4() {
        ExecutorService pool = Executors.newFixedThreadPool(2);
        CompletableFuture<String> futureA = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "\t---启动");
            try { TimeUnit.SECONDS.sleep(3); } catch (Exception e) { e.printStackTrace();}
            System.out.println("A come in");
            return "futureAA";
        },pool);
        CompletableFuture<String> futureB = CompletableFuture.supplyAsync(() -> {
            try { TimeUnit.SECONDS.sleep(2); } catch (Exception e) { e.printStackTrace();}
            System.out.println("B come in");
            return "futureBB";
        },pool);

        CompletableFuture<String> result = futureA.applyToEither(futureB, f -> f + " is winner");

        System.out.println(result.join());


        pool.shutdown();
    }

    /**
     * 对计算结果进行合并
     *
     */
    private static void test5() {
        ExecutorService pool = Executors.newFixedThreadPool(2);
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "\t---启动");
            try { TimeUnit.SECONDS.sleep(1); } catch (Exception e) { e.printStackTrace();}
            return 10;
        },pool);

        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "\t---启动");
            try { TimeUnit.SECONDS.sleep(2); } catch (Exception e) { e.printStackTrace();}
            return 20;
        },pool);

        CompletableFuture<Integer> future3 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "\t---启动");
            try { TimeUnit.SECONDS.sleep(3); } catch (Exception e) { e.printStackTrace();}
            return 50;
        },pool);

        CompletableFuture<Integer> result = future1.thenCombine(future2, (x, y) -> x + y).thenCombine(future3, (x, y) -> x + y);
        System.out.println(result.join());
        pool.shutdown();


    }

    public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
        test5();
    }


}
